#ifndef H_YS_VEC_
#define H_YS_VEC_

#include <cstring>
#include "ysMisc.hpp"

namespace n_ysUtil{

//template <typename T, int Dim> class vec;

template <typename T, int Dim>
struct vec
{
public:
	typedef T	typeElem;
	static const int VEC_DIM = Dim;
//ctors
	vec(){std::memset(m_data, 0, sizeof(m_data));}

	// same type
	vec(const vec<T, Dim>& other)
	{
		memcpy(this->m_data, other.m_data, sizeof(this->m_data));
	}

	// different type
	template<typename T1>
	vec(const vec<T1, Dim>& other)
	{
		for(int i=0; i<Dim; ++i)
		{
			m_data[i] = other.m_data[i];
		}
	}

	vec(const T* arr)
	{
		memcpy(this->m_data, arr, sizeof(this->m_data));
	}


	vec(const T val)
	{
		for(size_t i=0; i<Dim; ++i)
			this->m_data[i] = val;
	}

// 2D specific
public:
	template<typename T1>
	vec(const T1 x, const T1 y)
	{
		YS_STATIC_ASSERT(Dim == 2, ONLY_FOR_2D_CASE);
		this->m_data[0] = x;	this->m_data[1] = y;
	}

// operations
	template<typename T1>
	vec&	operator+=(const vec<T1, Dim>& rhs)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] += rhs.m_data[i];
		return (*this);
	}

	template<typename T1>
	vec	operator+ (const vec<T1, Dim>& rhs)const
	{
		vec<T1, Dim> ret(*this);
		return (ret += rhs);
	}

	template<typename T1>
	vec&	operator+=(const T1& a)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] += a;
		return (*this);
	}

	template<typename T1>
	vec	operator+ (const T1& a)const
	{
		vec<T1, Dim> ret(*this);
		return (ret += a);
	}

	template<typename T1>
	vec	operator-=(const vec<T1, Dim>& rhs)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] -= rhs.m_data[i];
		return (*this);
	}

	template<typename T1>
	vec	operator- (const vec<T1, Dim>& rhs)const
	{
		vec<T, Dim> ret(*this);
		return (ret -= rhs);
	}

	template<typename T1>
	vec	operator-=(const T1& s)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] -= s;
		return (*this);
	}

	template<typename T1>
	vec	operator- (const T1& s)const
	{
		vec<T, Dim> ret(*this);
		return (ret -= s);
	}

	template<typename T1>
	vec&	operator*=(const T1 factor)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] *= factor;
		return (*this);
	}

	template<typename T1>
	vec	operator* (const T1 factor)const
	{
		vec<T, Dim> ret(*this);
		return (ret *= factor);
	}

	template<typename T1>
	vec&	operator/=(const T1 factor)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] /= factor;
		return (*this);
	}

	template<typename T1>
	vec	operator/ (const T1 factor)const
	{
		vec ret(*this);
		return (ret /= factor);
	}

	//only for int type elem
	template<typename T1>
	vec&	operator%=(const T1 factor)
	{
		for(int i=0; i<Dim; ++i)
			m_data[i] %= factor;
		return (*this);
	}

	//only for int type elem
	template<typename T1>
	vec	operator% (const T1 factor)const
	{
		vec ret(*this);
		return (ret %= factor);
	}

	T& operator[] (int idx) {return m_data[idx];}
	T operator[] (int idx)const {return m_data[idx];}


	bool	operator== (const vec<T, Dim>& rhs)const
	{
		/*for(int i=0; i<Dim; ++i)
			if(this->m_data[i]!=rhs.m_data[i])	return false;
		return true;*/
		return std::memcmp(m_data, rhs.m_data, sizeof(m_data)) == 0;
	}

	bool	operator!= (const vec<T, Dim>& rhs)const
	{
		return !(operator==(rhs));
	}

	template<typename T1>
	bool	operator== (const vec<T1, Dim>& rhs)const
	{
		/*vec<T, Dim> cp(rhs);
		return (operator==(cp));*/
		for(int i=0; i<Dim; ++i)
			if(this->m_data[i]!=rhs.m_data[i])	return false;
		return true;
	}

	template<typename T1>
	bool	operator!= (const vec<T1, Dim>& rhs)const
	{
		return !(operator==(rhs));
	}

//data
//private:
	T m_data[Dim];
};

/*
template <typename T, int Dim>
class vec : public vecBase<T, Dim>
{
public:
	vec() : vecBase<T, Dim>() {}

	vec(const vecBase<T, Dim>& other)
		: vecBase<T, Dim>(other){}

	template<typename T1>
	vec(const vecBase<T1, Dim>& other)
		: vecBase<T1, Dim>(other){}

	vec(const T* arr)
		: vecBase<T, Dim>(arr){}

	vec(const T v)
		: vecBase<T, Dim>(v){}
};

//2D case
template <typename T>
class vec<T, 2> : public vecBase<T, 2>
{
// the same as the normal template
public:
	vec() : vecBase<T, 2>() {}

	vec(const vecBase<T, 2>& other)
		: vecBase<T, 2>(other){}

	template<typename T1>
	vec(const vecBase<T1, 2>& other)
		: vecBase<T, 2>(other){}

	vec(const T* arr)
		: vecBase<T, 2>(arr){}

	vec(const T v)
		: vecBase<T, 2>(v){}

// 2D specific
public:
	template<typename T1>
	vec(const T1 x, const T1 y)
	{
		this->m_data[0] = x;	this->m_data[1] = y;
	}

	//template<typename T1>
	//vec(const T1 v)
	//{
	//	this->m_data[0] = v;	this->m_data[1] = v;
	//}

	//template<typename T1>
	//vec(const vecBase<T1, 2>& other)
	//	:vecBase<T, 2>(other)
	//{}

// interfaces:
// 2D specific
public:
	T& X(){return this->m_data[0];}
	T& Y(){return this->m_data[1];}

	T X()const{return this->m_data[0];}
	T Y()const{return this->m_data[1];}

	template<typename T1>
	bool	operator== (const vec<T1, 2>& rhs)const
	{
		return( this->m_data[0]==rhs.m_data[0] && this->m_data[1]==rhs.m_data[1]);
	}

	template<typename T1>
	bool	operator!= (const vec<T1, 2>& rhs)const
	{
		return !(operator==(rhs));
	}
};


//TODO: implement 3D case
template <typename T>
class vec<T, 3> : public vecBase<T, 3>
{
public:

//interfaces:
public:
	T& X(){return this->m_data[0];}
	T& Y(){return this->m_data[1];}
	T& Z(){return this->m_data[2];}

	T X()const{return this->m_data[0];}
	T Y()const{return this->m_data[1];}
	T Z()const{return this->m_data[2];}
};
*/
}// namespace

#endif // header
